Voorbeeldoplossing Serialization Book
Home

Voorbeeldoplossing Serialization Book

Voorbeeldoplossing Serialization Book

Om de serialiseringstechnieken in te oefenen gaan we dezelfde methodes, die we gemaakt hebben voor Postcode, nu maken voor Book.

Opdracht

  1. Sla de XML hieronder op in een bestand met de naam Book.xml in de Data map.
    In het voorbeeld heb ik het bestand van Digitap gedownloaded.
  2. Maak een klassenbestand met de naam Book.cs, met daarin de klasse Book in de namespace DotNetCore.Learning. Baseer je op de structuur van het XML bestand om een Book object te maken met de overeenkomstige properties (de structuur staat beschreven in Ontwerpfase Book App).
    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace DotNetCore.Learning
    {
        public class Book
        {
            private string title;
    
            public string Title
            {
                get { return title; }
                set { title = value; }
            }
    
            private string year;
    
            public string Year
            {
                get { return year; }
                set { year = value; }
            }
    
            private string city;
    
            public string City
            {
                get { return city; }
                set { city = value; }
            }
    
            private string publisher;
    
            public string Publisher
            {
                get { return publisher; }
                set { publisher = value; }
            }
    
            private string author;
    
            public string Author
            {
                get { return author; }
                set { author = value; }
            }
    
            private string edition;
    
            public string Edition
            {
                get { return edition; }
                set { edition = value; }
            }
    
            private string translator;
    
            public string Translator
            {
                get { return translator; }
                set { translator = value; }
            }
    
            private string comment;
    
            public string Comment
            {
                get { return comment; }
                set { comment = value; }
            }
    
            private List<Book> list;
    
            public List<Book> List
            {
                get { return list; }
                set { list = value; }
            }
    
        }
    }
    
    
  3. Maak een klassenbestand met de naam BookSerializing.cs met daarin de klasse BookSerializing in de namespace DotNetCore.Learning.
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using System.Xml.Serialization;
    
    namespace DotNetCore.Learning
    {
        class BookSerializing
        {    
    
        }
    }
    
  4. In deze klasse maak je de volgende methoden:
    1. Vermits de opgegeven dataset in XML is beginnen we met een methode die het XML bestand deserialiseert naar een generieke lijst van boeken List<Book>. De naam van deze methode is DeserializeFromXml.
    2. Code:
      public static List<Book> DeserializeFromXml()
      {
          XmlSerializer serializer = new XmlSerializer(typeof(Book[]));
          Book book = new Book();
          StreamReader file = new System.IO.StreamReader(@"Data/Book.xml");
          Book[] books = (Book[])serializer.Deserialize(file);
          file.Close();
          // array converteren naar List
          return new List<Book>(books);
      }
      
    3. Schrijf een methode die de boeken in de generieke lijst toont in de console met de naam ShowBooks.
      public static void ShowBooks(List<Book> list)
      {
          foreach (Book item in list)
          {
              Console.WriteLine("{0}{1}{2}{3}{4}{5}{6}{7}",
                                  item?.Title,
                                  item?.Year,
                                  item?.City,
                                  item?.Publisher,
                                  item?.Author,
                                  item?.Edition,
                                  item?.Translator,
                                  item?.Comment);
          }
      }
    4. Uitproberen in Program.cs:
      using DotNetCore.Learning;
      using System;
      using System.Collections.Generic;
      
      namespace DontNetCore.Learning
      {
          class Program
          {
              static void Main(string[] args)
              {
                  Console.WriteLine("Gegevensserialisatie");
                  List<Book> books = BookSerializing.DeserializeFromXml();
                  BookSerializing.ShowBooks(books);
                  // TryOut.SerializeObjectToCsv(books, ";");
              }
          }
      }
      1. We krijgen de volgende foutmelding:
        InvalidOperationException: <Books xmlns=''> was not expected.
        Foutmelding bij XML inlezen
        Foutmelding bij XML inlezen
      2. We openen het Book.xml bestand in Kladblok en stellen vast dat de XML declaratie wel degelijk in het bestand staat. Je kan die manueel verwijderen uit het tekstbestand.
        XML declaratie voor Book
        XML declaratie voor Book en root van de XML boomstructuur
        Maar we zoeken op of het niet mogelijk is om dat programmatorisch te doen.
      3. Informatie over de fout opzoeken op het internet.
        Het eerste antwoord op de vraag is al meteen een goed antwoord! We moeten aan de XmlSerializer opgeven wat het root element is van onze XML.
      4. Verbeteren:
        public static List<Book> DeserializeFromXml()
        {
            XmlRootAttribute xRoot = new XmlRootAttribute();
            xRoot.ElementName = "Books";
            // xRoot.Namespace = "http://www.cpandl.com";
            xRoot.IsNullable = true;
            XmlSerializer serializer = new XmlSerializer(typeof(Book[]), xRoot);
            Book book = new Book();
            StreamReader file = new System.IO.StreamReader(@"Data/Book.xml");
            Book[] books = (Book[])serializer.Deserialize(file);
            file.Close();
            // array converteren naar List
            return new List<Book>(books);
        }
        Hiermee geven we aan dat de XmlSerializer de XML declaratie moet overslaan en met het root element Books moet beginnen.
      5. Video 1
      6. En opnieuw uitproberen:
        Probleem bij het inlezen XML lege regels en spaties
        Probleem bij het inlezen XML lege regels en spaties
        We hebben nu een ander probleem. Niet alle boeken worden correct ingelezen. Er staat een lege lijn en spaties aan het begin. Hoe pakken we dit probleem aan?
      7. We beginnen met de debuggen. We gaan kijken wat er precies wordt ingelezen in de books list. Zet een breakpoint naast de programmaregel waar de lijst wordt aangemaakt:
        breakpoint op de regel waar de books list wordt gemaakt
        breakpoint op de regel waar de books list wordt gemaakt
      8. Opnieuw runnen. Het programma stopt op regel 12. Klik op step over om regel 12 uit te voeren en inspecteer vervolgens de books list:
        Inspecteer de books list
        Inspecteer de books list
        Vervolgens op je rij 22, dat is de rij waar problemen zijn:
        Inspecteer rij 22 van de books list
        Inspecteer rij 22 van de books list
      9. Vanwaar komt die new line en die spaties in de Author property? We open Book.xml opnieuw in Kladblok:
        tags en tekst op verschillende regels
        tags en tekst op verschillende regels
      10. Dat is m.i. een fout in de XmlSerializer klasse. We kunnen dat oplossen door gebruik te maken van de setters van de Book klasse. Vooraleer een waarde toe te kennen aan Author en Title gaan we kijken als er new lines, dubbele spaties en spaties aan het begin in staan. Indien dit geval is, verwijderen we ze. Ik geef hier de setters voor Author en Title:
        public string Author
        {
            get { return author; }
            set
            {
                author = value.Replace("\n", string.Empty).Replace("  ", " ").TrimStart();
            }
        }
        
        public string Title
        {
            get { return title; }
            set
            {
                title = value.Replace("\n", string.Empty).Replace("  ", " ").TrimStart();
            }
        }
        
        Voor alle zekerheid pas je best alle setters aan.
      11. Verwijder de breakpoint en opnieuw runnen met dit als resultaat:
        Inlezen Book xml - lege lijn en spaties zijn verwijderd
        Inlezen Book xml - lege lijn en spaties zijn verwijderd
    5. Maak een methode met de naam SerializeListToCsv die een generieke lijst met boeken serialiseert naar een CSV bestand.
      Deze mthode is gebaseerd op de methode SerializeObjectToCsv die staat in Een generieke lijst serialiseren naar CSV.
      public static string SerializeListToCsv(List<Book> list, string fileName, string separator)
      {
          string message;
          try
          {
              TextWriter writer = new StreamWriter(fileName);
              foreach (Book item in list)
              {
                  // One of the most versatile and useful additions to the C# language in version 6
                  // is the null conditional operator ?.           
                  writer.WriteLine("{0}{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}{11}{12}{13}{14}",
                      item?.Title,
                      separator,
                      item?.Year,
                      separator,
                      item?.City,
                      separator,
                      item?.Publisher,
                      separator,
                      item?.Author,
                      separator,
                      item?.Edition,
                      separator,
                      item?.Translator,
                      separator,
                      item?.Comment);
              }
              writer.Close();
              message = $"Het bestand met de naam {fileName} is gemaakt!";
          }
          catch (Exception e)
          {
              // Melding aan de gebruiker dat iets verkeerd gelopen is.
              // We gebruiken hier de nieuwe mogelijkheid van C# 6: string interpolatie
              message = $"Kan het bestand met de naam {fileName} niet maken.\nFoutmelding {e.Message}.";
          }
          return message;
      }
    6. Maak een methode met de naam DeserializeCsvToList die een csv bestand omzet naar een lijst van het type List<Book>.
      Dit is iets ingewikkelder omdat we geen bestaande bibliotheek gebruiken.
      1. Een methode om een tekstbestand in te lezen
        We gebruiken daarvoor de methode Lees. De uitleg vind op Tekstbestanden inlezen.
        Maak een klassenbestand met de naam Tekstbestand.cs en plak daarin onderstaande code. Let erop dat de klasse staat in de namespace Helpers.
      2. Een methode om Book.csv in te lezen
        Deze methode is gebaseerd op de methode ReadPostcodesFromCSVFile uit CSV bestand deserialiseren naar een generieke lijst.
        public static string ReadBooksFromCSVFile()
        {
            Helpers.Tekstbestand bestand = new Helpers.Tekstbestand();
            bestand.FileName = @"Data/Book.csv";
            bestand.Lees();
            return bestand.Text;
        }
      3. Nu nog de methode die de string gegevens van een boek omzet naar een Book object
        Deze methode is gebaseerd op de methode PostcodeCsvToObject uit CSV bestand deserialiseren naar een generieke lijst.
        public static Book BookCsvToObject(string line, string separator)
        {
            Book book = new Book();
            string[] values = line.Split(separator);
            book.Title = values[0];
            book.Year = values[1];
            book.City = values[2];
            book.Publisher = values[3];
            book.Author = values[4];
            book.Edition = values[5];
            book.Translator = values[6];
            book.Comment = values[7];
            return book;
        }
      4. Tenslotte de DeserializeCsvToList methode maakt een lijst van book-objecten. De ReadPostcodesFromCSVFile methode retourneert een lange string. Elke regel in de string bevat de gegevens over 1 boek. We moeten die string dus splitsen op basis van een new line (\n) en elke regel stoppen we in een array. Dan doorlopen we elk element van de array. Elk element is een string met waarden die door een ; gescheiden zijn. Die string geven we door aan de BookCsvToObject methode om die te splitsen en zo bekomen waarden in een Book object te plaatsen.
        Deze methode is gebaseerd op ReadPostcodesFromCSVFile uit CSV bestand deserialiseren naar een generieke lijst.

        public static List<Book> DeserializeCsvToList(string separator)
        {
            string[] books = ReadBooksFromCSVFile().Split('\n');
            List<Book> list = new List<Book>();
            foreach (string s in books)
            {
                if (s.Length > 0)
                {
                    list.Add(BookCsvToObject(s, separator));
                }
            }
            return list;
        }
    7. Video 2
    8. Maak een methode met de naam SerializeListToJson die een generieke lijst met boeken serialiseert naar een json bestand.
      1. Installeer de laatste versie van Newtonsog.Json in NuGet Package Manager Console:
        Install-Package Newtonsoft.Json -Version 12.0.3
      2. De code is gebaseerd op de SerializeCsvToJson methode uit JSON en .NET Core.
        public static void SerializeListToJson(List<Book> list, string fileName)
        {
                TextWriter writer = new StreamWriter(fileName);
                // static method SerilizeObject van Newtonsoft.Json
            string postcodeString = Newtonsoft.Json.JsonConvert.SerializeObject(list);
            writer.WriteLine(postcodeString);
            writer.Close();
        }
      3. Uitproberen in de Main methode van de Program klasse:
        using DotNetCore.Learning;
        using System;
        using System.Collections.Generic;
        
        namespace DontNetCore.Learning
        {
            class Program
            {
                static void Main(string[] args)
                {
                    Console.WriteLine("Gegevensserialisatie");
                    List<Book> books = BookSerializing.DeserializeFromXml();
                    BookSerializing.ShowBooks(books);
                    TryOut.SerializeListToCsv(books, @"Data/Book.csv", ";");
                    books = TryOut.DeserializeCsvToList(";");
                    Console.WriteLine("".PadLeft(60, '*'));
                    Console.WriteLine("\n\n\nIngelezen van CSV bestand!\n\n\n");
                    Console.WriteLine("".PadLeft(60, '*'));
                    BookSerializing.ShowBooks(books);
                    TryOut.SerializeListToJson(books, @"Data/Book.json");
                }
            }
        }
      4. Als we kijken naar het gegenereerde json bestand stellen we vast dat er iets niet klopt:
        fouten in het JSON bestand
        fouten in het JSON bestand
      5. Hoe komt dat? We openen het CSV bestand dat we inlezen:
        er staat een puntkomma in de titel - an dus niet als separator gebruikt worden
        er staat een puntkomma in de titel - an dus niet als separator gebruikt worden
      6. We herschrijven de code in de Main methode van de Program klasse en gebruiken een andere separator
        using DotNetCore.Learning;
        using System;
        using System.Collections.Generic;
        
        namespace DontNetCore.Learning
        {
            class Program
            {
                static void Main(string[] args)
                {
                    Console.WriteLine("Gegevensserialisatie");
                    List<Book> books = BookSerializing.DeserializeFromXml();
                    BookSerializing.ShowBooks(books);
                    TryOut.SerializeListToCsv(books, @"Data/Book.csv", "|");
                    books = TryOut.DeserializeCsvToList("|");
                    Console.WriteLine("".PadLeft(60, '*'));
                    Console.WriteLine("\n\n\nIngelezen van CSV bestand!\n\n\n");
                    Console.WriteLine("".PadLeft(60, '*'));
                    BookSerializing.ShowBooks(books);
                    TryOut.SerializeListToJson(books, @"Data/Postcode.json");
                }
            }
        }
        
      7. Ziet er veel beter uit:
        Book JSON correct gegenereerd
        Book JSON correct gegenereerd
      8. Er bestaan online JSON editors. Knip en plak de inhoud van Book.json in de editor:
        geformatteerde Book json
        geformatteerde Book json
    9. Maak een methode met de naam DeserializeJsonToList die een json bestand omzet naar een lijst van het type List<Book>.
      1. De code is gebaseerd op de GetPostcodeListFromJson methode uit JSON en .NET Core .
        public static List<Book> DeserializeJsonToList(string fileName)
        {
            Helpers.Tekstbestand bestand = new Helpers.Tekstbestand();
            bestand.FileName = fileName;
            bestand.Lees();
            List<Book> list = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Book>>(bestand.Text);
            return list;
        }
      2. Uitproberen in de Main methode van de Program klasse:
        using DotNetCore.Learning;
        using System;
        using System.Collections.Generic;
        
        namespace DontNetCore.Learning
        {
            class Program
            {
                static void Main(string[] args)
                {
                    Console.WriteLine("Gegevensserialisatie");
                    List<Book> books = BookSerializing.DeserializeFromXml();
                    BookSerializing.ShowBooks(books);
                    TryOut.SerializeListToCsv(books, "|");
                    books = TryOut.DeserializeCsvToList("|");
                    Console.WriteLine("".PadLeft(60, '*'));
                    Console.WriteLine("\n\n\nIngelezen van CSV bestand!\n\n\n");
                    Console.WriteLine("".PadLeft(60, '*'));
                    BookSerializing.ShowBooks(books);
                    TryOut.SerializeListToJson(books, @"Data/Book.json");
                    books = TryOut.DeserializeJsonToList(@"Data/Book.json");
                    Console.WriteLine("".PadLeft(60, '*'));
                    Console.WriteLine("\n\n\nIngelezen van JSON bestand!\n\n\n");
                    Console.WriteLine("".PadLeft(60, '*'));
                    BookSerializing.ShowBooks(books);
                }
            }
        }
        
        
      3. Resultaat:
        Resulaat JSON bestand deserialiseren
        Resulaat JSON bestand deserialiseren
  5. Video 3
  6. Probeer elk van deze methoden uit in de main methode van de Program klasse in Program.cs.
    Ik heb die methoden al hierboven uitgeprobeerd. Maar je kan het nog anders doen, door bijvoorbeeld een andere seperator te gebruiken. Of een XML bestand in te lezen zonder XML declaratie, enz.

JI
2020-10-24 13:40:18